// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WOBJECT_H_
#define WOBJECT_H_

#include <Wt/WDllDefs.h>
#include <Wt/WGlobal>
#include <Wt/Http/Request>

namespace Wt {
  /*! \brief Namespace for signal/slot implementation
   *
   * Namespace Wt::Signals offers classes for connecting signals to handlers
   * of those signals. The underlying implementation is configurable, and
   * some details may be different from one configuration to the other, but
   * the common basis is documented here.
   *
   * For now, %Wt's signals implementations are based on boost's signals
   * implementation. %Wt wraps these implementations in its own Wt::Signal
   * class, so you don't interact immediately with this object. Refer to
   * the documentation of Wt::Signal for the API description. Connection
   * lifetime management however depends on the underlying signals
   * implementation.
   *
   * A call to Wt::Signal::connect() returns a class of type
   * Wt::Signals::connection. This class allows for manual connection
   * management: if you ever want to disconnect a signal, keep a copy of the
   * connection object and invoke connection.disconnect(). Usually, you will
   * use automatic connection management as described below.
   *
   * %Wt's signal/slot implementation offers automatic connection management
   * through object lifetime tracking. With automatic connection management,
   * a signal will be disconnected when the signal's target object is
   * deleted. This lifetime tracking works, provided that the classes whose
   * lifetime has to be tracked inherit from WObject, and that the
   * Wt::WSignal class is able to detect the presence of the WObject
   * class.
   *
   * Since WObject is a base class for WWidget, the first condition
   * is fullfilled for all of %Wt's widgets, classes inheriting from widgets,
   * and other classes that inherit from WObject. For your own classes, you may
   * inherit from WObject in order to activate automatic
   * lifeteime tracking.
   *
   * The second condition, the ability for the signals library to detect this
   * WObject class, you have to know for which situations lifetime tracking
   * is supported - for all other cases, assume it's not supported. The ability
   * for the signals implementation to detect the lifetime tracked objects,
   * depends on how you invoke the connect() method.
   *
   * Any connect call where you pass the receiver of the signal directly
   * to the Wt::WSignal::connect() method as first parameter, is ok. If the
   * receiver inherits from WObject, the signal will be disconnected when
   * the receiver is deleted.
   *
   * In general, connection tracking does not work for the
   * Wt::WSignal::connect(const F &function) method. The only exception is
   * when the function pointer object was created by boost::bind, in which case
   * the receiver object (inheriting from WObject) will be tracked.
   *
   * Practical guidelines:
   * - use WSignal::connect with an explicit target parameter for connecting
   *   to slots which are member methods and for which no binding is required.
   *   This first parameter is a class derived from WObject (or inheriting
   *   from Wt::Signals::trackable, for boost signal/slot implementations)
   * - use std::bind for lambda functions, as these are not as good supported by
   *   boost::bind as std::bind. Remember that automatic connection management
   *   will not work - connecting to the signals of the receiver itself or a
   *   signal of one of its signals is generally safe, but connecting to a
   *   signal from outside your own descendants likely requires additional
   *   measurements to ensure proper lifetime tracking.
   * - use boost::bind for all other bindings, as this will offer you automatic
   *   lifetime management.
   *
   * %Wt used boost.signal (v1) as underlying implementation for its signal/slot
   * system. Since boost 1.54, boost.signal has been marked deprecated, being
   * replaced by boost.signals2. The WT_SIGNALS_IMPLEMENTATION cmake defines
   * allows you to switch between the available implementation for Wt::Signals.
   * There may be other signal/slot libraries supported in the future. With
   * the boost implementations, %Wt relies on boost::trackable for the
   * implementation of object lifetime tracking for connection management,
   * meaning that WObject inherits from boost.trackable.
   *
   * The classes of Wt::Signals are to be considered as not thread safe. Since
   * Wt has a per-session locking mechanism, under the form of the
   * WApplication::UpdateLock, this is hardly an issue. The boost.signals2
   * implementation offers some degree of thread-safety; please ensure to
   * understand its details before relying on it.
   *
   * \ingroup signalslot
   */
  namespace Signals {
#ifdef DOXYGEN_ONLY
    /*! \brief Base class for lifetime-tracked objects
     *
     */
    typedef implementation_defined trackable;

    /*! \brief Implementation-defined class representing a connection
     *
     * This object can be used to manually disconnect a signal-slot connection.
     * For boost signals, the disconnect() member disconnects the connection.
     */
    typedef implementation_defined connection;
#endif
  }
}

#if defined(WT_USE_BOOST_SIGNALS)

#include <boost/signals/trackable.hpp>
#include <boost/signal.hpp>

namespace Wt {
  namespace Signals {
    using boost::signal;
    using boost::signal0;
    using boost::signal1;
    using boost::signal2;
    using boost::signal3;
    using boost::signal4;
    using boost::signal5;
    using boost::signal6;
    using boost::signals::trackable;
    using boost::signals::connection;
    using boost::signals::at_front;
  }
}

#elif defined(WT_USE_BOOST_SIGNALS2)

#include <boost/smart_ptr/weak_ptr.hpp>
#include <boost/signals2/trackable.hpp>
#include <boost/signals2.hpp>
namespace Wt {
  namespace Signals {
    using boost::signals2::signal;
    using boost::signals2::trackable;
    using boost::signals2::connection;
    using boost::signals2::at_front;
    // Note: signal0-6 are not available in signals2 if the compiler supports
    // variadic templates
  }
}

// see https://svn.boost.org/trac/boost/ticket/10100
#define TRACKABLE_BROKEN

#endif

#include <cassert>
#include <vector>
#include <map>

namespace Wt {

class JavaScriptEvent;

struct WT_API NoClass
{
  NoClass() { }
  NoClass(const JavaScriptEvent&) { }

  static NoClass none;
};

#ifndef WT_CNOR
template <typename A1, typename A2, typename A3,
	  typename A4, typename A5, typename A6>
  class Signal;
#endif // WT_CNOR

class WStatelessSlot;

/*! \class WObject Wt/WObject Wt/WObject
 *  \brief A base class for objects that participate in the signal/slot system.
 *
 * The main feature offered by %WObject is automated object life-time
 * tracking when involved in signal/slot connections. Connections
 * between signals and slots of %WObject instances implement a
 * type-safe event callback system. For example, one can simply
 * connect() the WInteractWidget::clicked() signal of a WPushButton to
 * the WApplication::quit() method, to exit the application when the
 * button is clicked:
 *
 * \code
 * Wt::WInteractWidget *sender = new Wt::WText("Quit.");
 * Wt::WApplication *app = Wt::WApplication::instance();
 * sender->clicked().connect(app, &Wt::WApplication::quit);
 * \endcode
 *
 * %Wt's signals may also propagate arguments to slots. For example,
 * the same clicked() signal provides event details in
 * a WMouseEvent details class, and these details may be received in
 * the slot:
 * \code
 * class MyClass : public Wt::WContainerWidget
 * {
 * public:
 *   MyClass(Wt::WContainerWidget *parent = 0)
 *     : Wt::WContainerWidget(parent)
 *   {
 *     Wt::WText *text = Wt::WText("Click here", this);
 *     text->clicked().connect(this, &MyClass::handleClick);
 *
 *     ...
 *   }
 *
 * private:
 *   void handleClick(const Wt::WMouseEvent& event) {
 *     if (event.modifiers() & Wt::ShiftModifier) {
 *       ...
 *     }
 *   }
 * };
 * \endcode
 * As the example illustrates, slots are ordinary %WObject methods.
 *
 * A second feature of %WObject is that they allow ownership
 * organization in ownership object trees. When an object is created
 * with another object as parent, it's ownership is transferred to the
 * parent. If not deleted explicitly, the child object will be deleted
 * together with the parent. Child objects may also be deleted
 * manually: they will remove themselves from their parent in the
 * process.
 *
 * In conjunction with EventSignal, %WObject also facilitates learning
 * of client-side event handling (in JavaScript) through invocation of
 * the slot method. This is only possible when the slot behaviour is
 * stateless, i.e. independent of any application state, and can be
 * specified using the implementStateless() methods.
 *
 * \sa Signal, EventSignal
 *
 * \ingroup signalslot
 */
class WT_API WObject : public Wt::Signals::trackable
{
public:
  /*! \brief Typedef for a %WObject method without arguments.
   */
  typedef void (WObject::*Method)();

  /*! \brief Create a %WObject with a given parent object.
   * 
   * If the optional parent is specified, the parent object will
   * destroy all child objects. Set parent to \c 0 to create an object
   * with no parent.
   *
   * \sa addChild()
   */
  WObject(WObject* parent = 0);

  /*! \brief Destructor.
   *
   * This automatically:
   * - deletes all child objects
   * - invalidates this object as sender or receiver in signals and slots
   */
  virtual ~WObject();  

  /*
   * Unique id's
   */
  unsigned rawUniqueId() const { return id_; }
  const std::string uniqueId() const;

  /*! \brief Returns the (unique) identifier for this object
   *
   * For a %WWidget, this corresponds to the id of the DOM element
   * that represents the widget. This is not entirely unique, since a
   * \link WCompositeWidget composite widget\endlink shares the same
   * id as its implementation.
   *
   * By default, the id is auto-generated, unless a custom id is set
   * for a widget using WWidget::setId(). The auto-generated id is created
   * by concatenating objectName() with a unique number.
   *
   * \sa WWidget::jsRef()
   */
  virtual const std::string id() const;

  /*! \brief Sets an object name.
   *
   * The object name can be used to easily identify a type of object
   * in the DOM, and does not need to be unique. It will usually
   * reflect the widget type or role. The object name is prepended to
   * the auto-generated object id().
   *
   * The default object name is empty.
   *
   * \note Only letters ([A-Za-z]), digits ([0-9]), hyphens ("-"),
   * underscores ("_"), colons (":"), and periods (".") are allowed in
   * the id.
   *
   * \sa id()
   */
  virtual void setObjectName(const std::string& name);

  /*! \brief Returns the object name.
   *
   * \sa setObjectName()
   */
  virtual std::string objectName() const;

  /*! \brief Resets learned stateless slot implementations.
   *
   * Clears the stateless implementation for all slots declared to be
   * implemented with a stateless implementation.
   *
   * \sa resetLearnedSlot(), implementStateless() 
   */
  void resetLearnedSlots();

  /*! \brief Resets a learned stateless slot implementation.
   *
   * Clears the stateless implementation for the given slot that
   * was declared to be implemented with a stateless implementation.
   *
   * When something has changed that breaks the contract of a
   * stateless slot to always have the same effect, you may call this
   * method to force the application to discard the current
   * implementation.
   *
   * \sa implementStateless()
   */
  template <class T>
    void resetLearnedSlot(void (T::*method)());
   
  /*! \brief Declares a slot to be stateless and learn client-side behaviour
   *         on first invocation.
   *
   * Indicate that the given slot is stateless, and meets the requirement
   * that the slot's code does not depend on any state of the object, but
   * performs the same visual effect regardless of any state, or at
   * least until resetLearnedSlot() is called.
   *
   * When this slot is connected to an EventSignal (such as those exposed
   * by WInteractWidget and WFormWidget), the %Wt library may decide to
   * cache the visual effect of this slot in JavaScript code at client-side:
   * this effect will be learned automatically at the first invocation.
   * This has no consequences for the normal event handling, since the slot
   * implementation is still executed in response to any event notification.
   * Therefore, it is merely an optimization of the latency for the visual
   * effect, but it does not change the behaviour of the application.
   *
   * When for some reason the visual effect does change, one may use
   * resetLearnedSlot() or resetLearnedSlots() to flush the existing cached
   * visual effect, forcing the library to relearn it.
   *
   * It is crucial that this function be applied first to a slot that is 
   * intended to be stateless before any %EventSignal connects to that slot.
   * Otherwise, the connecting %EventSignal cannot find the stateless
   * slot implementation for the intended slot, and the statement will have
   * no effect for that connection.
   *
   * \sa resetLearnedSlot(), EventSignal
   */
#ifndef WT_TARGET_JAVA
  template <class T>
    WStatelessSlot *implementStateless(void (T::*method)());
#else // WT_TARGET_JAVA
  template <class T1>
    WStatelessSlot *implementStateless(T1 method);
#endif // WT_TARGET_JAVA

  /*! \brief Declares a slot to be stateless and learn client-side behaviour
   *         in advance.
   *
   * This method has the same effect as
   *\link implementStateless() implementStateless(void (T::*method)())\endlink,
   * but learns the visual effect of the slot before the first
   * invocation of the event.
   *
   * To learn the visual effect, the library will simulate the event and
   * record the visual effect. To restore the application state, it will
   * call the undoMethod which must restore the effect of method. 
   *
   * \sa \link implementStateless() implementStateless(void (T::*method)())\endlink
   */
#ifndef WT_TARGET_JAVA
  template <class T>
    WStatelessSlot *implementStateless(void (T::*method)(),
				       void (T::*undoMethod)());
#else // WT_TARGET_JAVA
  template <class T1, class T2>
    WStatelessSlot *implementStateless(T1 method, T2 undoMethod);
#endif // WT_TARGET_JAVA

  /*! \brief Marks the current function as not stateless.
   *
   * This may be useful if your current function is manipulating the
   * UI in a way that is not stateless (i.e. does depend on some
   * state), but which happens to be called from within a function
   * that is marked stateless (such as WWidget::setHidden()). This
   * will reject stateless slot pre-learning in this case, reverting
   * to plain server-side dynamic UI updates.
   */
  void isNotStateless();

  /*! \brief Provides a JavaScript implementation for a method
   *
   * This method sets the JavaScript implementation for a method. As a
   * result, if JavaScript is available, the JavaScript version will
   * be used on the client side and the visual effect of the C++
   * implementation will be ignored.
   *
   * This is very similar to an auto-learned stateless slot, but here the
   * learning is avoided by directly setting the JavaScript implementation.
   *
   * The \p jsCode should be one or more valid JavaScript statements.
   *
   * \sa \link implementStateless() implementStateless(void (T::*method)())\endlink
   */
  template <class T>
    WStatelessSlot *implementJavaScript(void (T::*method)(),
					const std::string& jsCode);

  /*! \brief Adds a child object.
   *
   * Take responsibility of deleting the child object, together with this
   * object.
   *
   * \sa removeChild()
   */
  void addChild(WObject *child);

  /*! \brief Removes a child object.
   *
   * The child must have been previously added.
   *
   * \sa addChild()
   */
  virtual void removeChild(WObject *child);

  /*! \brief Returns the children.
   */
  const std::vector<WObject *>& children() const;
 
  /*! \brief Returns the parent object.
   */
  WObject *parent() const { return parent_; }

#ifndef WT_CNOR
  Signal<WObject *, NoClass, NoClass, NoClass, NoClass, NoClass>& destroyed();
#endif // WT_CNOR

  virtual bool hasParent() const;

  static void seedId(unsigned id);

  /* Class that can be used to check if a WObject is deleted.
   *
   * Usage example:
   * {
   *   DeletionTracker guard(this);
   *   changed_.emit();
   *   if (!guard.deleted())
   *     changedTo_.emit(currentValue);
   * }
   */
  class DeletionTracker {
  public:
    DeletionTracker(WObject *trackable);
    bool deleted() const;
  private:
#ifndef WT_TARGET_JAVA
#ifndef TRACKABLE_BROKEN
    Wt::Signals::signal<void()> signal_;
    Wt::Signals::connection connection_;
#else
    boost::weak_ptr<int> ptr;
#endif
#endif
  };

protected:
  virtual void signalConnectionsChanged();

  /*! \brief Returns the sender of the current slot call.
   *
   * Use this function to know who emitted the signal that triggered this
   * slot call. It may be \c 0 if the signal has no owner information, or
   * if there is no signal triggering the current slot, but instead the slot
   * method is called directly.
   */
  static WObject *sender();

  virtual void setParent(WObject *parent);

  struct FormData {
    FormData(const Http::ParameterValues& aValues,
	     const std::vector<Http::UploadedFile>& aFiles)
      : values(aValues), files(aFiles) { }

    const Http::ParameterValues& values;
    std::vector<Http::UploadedFile> files;
  };

  virtual void setFormData(const FormData& formData);
  virtual void setRequestTooLarge(::int64_t size);

  /*! \brief On-demand stateless slot implementation.
   *
   * This method returns a stateless slot implementation for the given
   * \p method. To avoid the cost of declaring methods to be
   * stateless when they are not used, you may reimplement this method
   * to provide a stateless implementation for a method only when the
   * method is involved in a slot connection.
   *
   * Use implementStateless() to provide a stateless implementation of the
   * given \p method, or return the base class implementation otherwise.
   */
  virtual WStatelessSlot *getStateless(Method method);

private:
  WStatelessSlot *implementPrelearn(Method method, Method undoMethod);
  WStatelessSlot *implementPrelearned(Method method, const std::string& jsCode);
  WStatelessSlot *implementAutolearn(Method method);
  void resetLearnedSlot(Method method);

  WStatelessSlot* isStateless(Method method);
  std::vector<WStatelessSlot *> statelessSlots_;

  WObject(const WObject&);
  WObject &operator =(const WObject &);

  unsigned    id_;
  std::string name_;

  static unsigned nextObjId_;

  std::vector<WObject *> *children_;
  WObject                *parent_;

#ifndef WT_CNOR
  Signal<WObject *, NoClass, NoClass, NoClass, NoClass, NoClass> *destroyed_;
#endif // WT_CNOR

  static std::vector<WObject *> emptyObjectList_;

#ifndef WT_CNOR
  template <typename E> friend class EventSignal;
  template <typename A1, typename A2, typename A3,
            typename A4, typename A5, typename A6> friend class JSignal;
#endif // WT_CNOR

#ifdef TRACKABLE_BROKEN
  boost::shared_ptr<int> trackable_ptr_;
#endif

  friend class EventSignalBase;
  friend class WebSession;
};

template <class T>
void WObject::resetLearnedSlot(void (T::*method)())
{
  assert(dynamic_cast<T *>(this));
  resetLearnedSlot(static_cast<Method>(method));
}

#ifndef WT_TARGET_JAVA
template <class T>
WStatelessSlot *WObject::implementStateless(void (T::*method)())
{
  assert(dynamic_cast<T *>(this));
  return implementAutolearn(static_cast<Method>(method));
}

template <class T>
WStatelessSlot *WObject::implementStateless(void (T::*method)(),
					    void (T::*undoMethod)())
{
  assert(dynamic_cast<T *>(this));
  return implementPrelearn(static_cast<Method>(method),
			   static_cast<Method>(undoMethod));
}
#endif // WT_TARGET_JAVA

template <class T>
WStatelessSlot *WObject::implementJavaScript(void (T::*method)(),
					     const std::string& jsCode)
{
  assert(dynamic_cast<T *>(this));
  return implementPrelearned(static_cast<Method>(method), jsCode);
}

}

#ifdef USING_NAMESPACE_WT
using namespace Wt;
#endif // USING_NAMESPACE_WT

#endif // WOBJECT_H_
